# 作者： 李泉志
# 2025年01月06日22时00分秒
# 2947029073@qq.com

"""
01. 函数参数和返回值的作用
函数根据有没有参数以及有没有返回值，可以相互组合，一共有4种组合形式
1. 无参数，无返回值
2. 无参数，有返回值
3. 有参数，无返回值
4. 有参数，有返回值

1.1 无参数，无返回值
此类函数，不接收参数，也没有返回值，应用场景如下：
1. 只是单纯地做一件事情，例如显示菜单
2. 在函数内部针对全局变量进行操作，例如：新建名片，最终结果记录在全局变量中
注意：
• 如果全局变量的数据类型是一个可变类型，在函数内部可以使用方法修改全局变量的内容 —— 变量的引用不会改变
• 在函数内部，使用赋值语句才会修改变量的引用

1.2 无参数，有返回值
此类函数，不接收参数，但是有返回值，应用场景如下：
• 采集数据，例如温度计，返回结果就是当前的温度，而不需要传递任何的参数

1.3 有参数，无返回值
此类函数，接收参数，没有返回值，应用场景如下：
• 函数内部的代码保持不变，针对不同的参数处理不同的数据
• 例如名片管理系统针对找到的名片做修改、删除操作

1.4 有参数，有返回值
此类函数，接收参数，同时有返回值，应用场景如下：
• 函数内部的代码保持不变，针对不同的参数处理不同的数据，并且返回期望的处理结果
• 例如名片管理系统 使用字典默认值和提示信息 提示用户输入内容
– 如果输入，返回输入内容
– 如果没有输入，返回字典默认值
"""

"""
02. 函数的返回值进阶
• 在程序开发中，有时候，会希望一个函数执行结束后，告诉调用者一个结果，以便调用者针对具体的结果做后续的处理
• 返回值是函数完成工作后，最后给调用者的一个结果
• 在函数中使用 return 关键字可以返回结果
• 调用函数一方，可以使用变量来接收函数的返回结果
问题：一个函数执行后能否返回多个结果？——多个
"""


def measure():
    """返回当前的温度和适度"""
    print("开始测量...")
    temp = 39
    wetness = 10
    print("测量结束...")
    return temp, wetness  # return (temp, wetness)


"""
03. 函数的参数 进阶
3.1. 不可变和可变的类型
问题 1：在函数内部，针对参数使用赋值语句，不会影响调用函数时传递的实参变量
• 无论传递的参数是可变还是不可变
    – 只要针对参数使用赋值语句，会在函数内部修改局部变量的引用，
    不会影响到外部变量的引用

问题 2：如果传递的参数是 可变类型，在函数内部，使用方法修改了数据的内容，同样会影响到
外部的数据

3.2 缺省参数
• 定义函数时，可以给某个参数指定一个默认值，具有默认值的参数就叫做缺省参数
• 调用函数时，如果没有传入缺省参数的值，则在函数内部使用定义函数时指定的参数默认值
• 函数的缺省参数，将常见的值设置为参数的缺省值，从而简化函数的调用
"""


def func1(num, num_list1, num_list2):
    print("函数内部代码")
    num += num  # 不可变类型
    num_list1 += [4, 5, 6]  # 变 等价于extend
    # num_list1.extend([4, 5, 6])

    num_list2 = num_list2 + [7, 8, 9]  # 不变
    print(num)
    print(num_list1)
    print(num_list2)
    print("函数结束")


"""
缺省参数的注意事项
1) 缺省参数的定义位置
• 必须保证带有默认值的缺省参数 在参数列表末尾
• 所以，以下定义是错误的！
def print_info(name, gender=True, title):
2) 调用带有多个缺省参数的函数
• 在调用函数时，如果有多个缺省参数，需要指定参数名，这样解释器才能够
知道参数的对应关系！如果都不指定是可以的，指定一个以后，后面的就必
须指定
"""


# 缺省参数
def test_func1(num=1):
    print(num)


def test_func2(name, num=1):
    print(name, num)


# test_func2('hello')  # 对

# def test_func3(num=1, name)  # 错 非缺省不能放缺省后面
# print(name, num)
"""
3.3 多值参数
定义支持多值参数的函数
• 有时可能需要一个函数能够处理的参数个数是不确定的，这个时候，就可以使用多值参数
• python中有两种多值参数：
    – 参数名前增加一个*可以接收 元组
    – 参数名前增加两个*可以接收 字典
• 一般在给多值参数命名时，习惯使用以下两个名字
    – *args —— 存放元组参数，前面有一个*
    – **kwargs —— 存放字典参数，前面有两个*
• args是arguments 的缩写，有变量的含义
• kw是keyword 的缩写，kwargs 可以记忆 键值对参数
• *args 必须在**kwargs 前面
"""


def demo2(num, *args, **kwargs):
    print(num)
    print(args)
    print(kwargs)


def demo(num, *args, **kwargs):
    print(num)
    print(args)
    print(kwargs)
    demo2(num, *args, **kwargs)  # 多值传参加*
    # 若不加*，则args以一个变量传进去作为元组的一个元素，kwargs一样，字典为空
    demo2(num, args, kwargs)

def demo3(*args, **kwargs):
    print(*args)
    print(kwargs)  #wrong:不能直接打印字典，需要用**kwargs打印


"""
元组和字典的拆包（掌握）
• 在调用带有多值参数的函数时，如果希望：
    – 将一个元组变量，直接传递给args
    – 将一个字典变量，直接传递给kwargs
• 就可以使用拆包，简化参数的传递，拆包的方式是：
    – 在元组变量前，增加一个*，代表元组拆包
    – 在字典变量前，增加两个*，代表字典拆包
"""

if __name__ == '__main__':
    # result = measure()
    # print(result)  # 用一个参数接所有,元组类型
    # ret1, ret2 = measure()  # 拆包，个数要对上
    # print(ret1, ret2)
    # print('-' * 50)
    #
    # # 利用元组swap
    # a = 10
    # b = 20
    # a, b = b, a  # 元组拆包
    # print(a, b)
    # print('-' * 50)
    #
    # # 参数变化
    # g_num = 10
    # g_list1 = [1, 2, 3]
    # g_list2 = [4, 5, 6]
    # func1(g_num, g_list1, g_list2)
    # print(g_num)  # 不变
    # print(g_list1)  # 变
    # print(g_list2)  # 不变
    # print('-' * 50)
    #
    # # 多值参数
    # demo(1, 2, 3, 4, 5, name="小明", age=18, gender=True)
    pass

